/**
 * Created by nengjian on 2017/4/17.
 */
var Promise = require('bluebird'),
    _       = require('lodash'),
    path    = require('path');
utils = {
    globalDefaultOptions: ['context', 'include'],
    dataDefaultOptions: ['data'],
    browseDefaultOptions: ['page', 'limit', 'fields', 'filter', 'order', 'debug'],
    idDefaultOptions: ['id'],

    validate: function validate(docName, extras) {
        return function doValidate() {
            var object, options, permittedOptions;
            if (arguments.length === 2) {
                object = arguments[0];
                options = _.clone(arguments[1]) || {};
            } else if (arguments.length === 1) {
                options = _.clone(arguments[0]) || {};
            } else {
                options = {};
            }

            permittedOptions = utils.globalDefaultOptions;

            // Add extra permitted options if any are passed in
            if (extras && extras.opts) {
                permittedOptions = permittedOptions.concat(extras.opts);
            }

            // This request will have a data key added during validation
            if ((extras && extras.attrs) || object) {
                permittedOptions = permittedOptions.concat(utils.dataDefaultOptions);
            }

            // If an 'attrs' object is passed, we use this to pick from options and convert them to data
            if (extras && extras.attrs) {
                options.data = _.pick(options, extras.attrs);
                options = _.omit(options, extras.attrs);
            }

            /**
             * ### Check Options
             * Ensure that the options provided match exactly with what is permitted
             * - incorrect option keys are sanitized
             * - incorrect option values are validated
             * @param {object} options
             * @returns {Promise<options>}
             */
            function checkOptions(options) {
                // @TODO: should we throw an error if there are incorrect options provided?
                options = _.pick(options, permittedOptions);

                var validationErrors = utils.validateOptions(options);

                if (_.isEmpty(validationErrors)) {
                    return Promise.resolve(options);
                }

                // For now, we can only handle showing the first validation error
                return errors.logAndRejectError(validationErrors[0]);
            }

            // If we got an object, check that too
            if (object) {
                // return utils.checkObject(object, docName, options.id).then(function (data) {
                //     options.data = data;
                //
                //     return checkOptions(options);
                // });
            }

            return checkOptions(options)
        }
    },
    validateOptions: function validateOptions(options) {
        var globalValidations = {
                id: {matches: /^\d+|me$/},
                uuid: {isUUID: true},
                slug: {isSlug: true},
                page: {matches: /^\d+$/},
                limit: {matches: /^\d+|all$/},
                fields: {matches: /^[\w, ]+$/},
                order: {matches: /^[a-z0-9_,\. ]+$/i},
                name: {}
            },
            // these values are sanitised/validated separately
            noValidation = ['data', 'context', 'include', 'filter'],
            errors = [];

        _.each(options, function (value, key) {
            // data is validated elsewhere
            if (noValidation.indexOf(key) === -1) {
                if (globalValidations[key]) {
                    errors = errors.concat(validation.validate(value, key, globalValidations[key]));
                } else {
                    // all other keys should be alpha-numeric with dashes/underscores, like tag, author, status, etc
                    errors = errors.concat(validation.validate(value, key, globalValidations.slug));
                }
            }
        });

        return errors;
    },
    handlePublicPermissions: function handlePublicPermissions(docName, method) {
        var singular = docName.replace(/s$/, '');

        /**
         * Check if this is a public request, if so use the public permissions, otherwise use standard canThis
         * @param {Object} options
         * @returns {Object} options
         */
        return function doHandlePublicPermissions(options) {
            // var permsPromise;
            //
            // if (utils.detectPublicContext(options)) {
            //     permsPromise = utils.applyPublicPermissions(docName, method, options);
            // } else {
            //     permsPromise = permissions.canThis(options.context)[method][singular](options.data);
            // }
            //
            // return permsPromise.then(function permissionGranted() {
            //     return options;
            // }).catch(function handleError(error) {
            //     return errors.formatAndRejectAPIError(error);
            // });
        };
    },

    convertOptions: function convertOptions(allowedIncludes) {
        /**
         * Convert our options from API-style to Model-style
         * @param {Object} options
         * @returns {Object} options
         */
        return function doConversion(options) {
            if (options.include) {
                options.include = utils.prepareInclude(options.include, allowedIncludes);
            }
            if (options.fields) {
                options.columns = utils.prepareFields(options.fields);
                delete options.fields;
            }
            return options;
        };
    },
    detectPublicContext: function detectPublicContext(options) {
        // options.context = permissions.parseContext(options.context);
        // return options.context.public;
    },
    reqsuccess:function reqsuccess(options) {
        return {
            data: options.data,
            ret_code: "000100",
        };
    },
    reqfailed:function reqsuccess(options) {
        return {
            ret_msg: options.msg,
            ret_code: "000000",
        };
    }
}

module.exports = utils;
